package com.bestcem.xm.txtanls.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONArray;
import com.bestcem.xm.common.core.domain.web.ServiceResult;
import com.bestcem.xm.common.core.uitls.StringUtil;
import com.bestcem.xm.txtanls.dao.*;
import com.bestcem.xm.txtanls.entity.mysql.TrainModelDo;
import com.bestcem.xm.txtanls.entity.pojo.HiddenKeywordDO;
import com.bestcem.xm.txtanls.entity.pojo.IndustryKeywordDO;
import com.bestcem.xm.txtanls.entity.pojo.ProjectDO;
import com.bestcem.xm.txtanls.entity.pojo.TopicDO;
import com.bestcem.xm.txtanls.enums.IndustryCodeEnum;
import com.bestcem.xm.txtanls.enums.IndustryKeyWordStatusEnum;
import com.bestcem.xm.txtanls.enums.KeywordOperationEnum;
import com.bestcem.xm.txtanls.grpc.client.BaseUserGrpcService;
import com.bestcem.xm.txtanls.grpc.convert.TopicConvert;
import com.bestcem.xm.txtanls.grpc.service.param.keyword.ListKeywordParam;
import com.bestcem.xm.txtanls.grpc.service.param.keyword.UpdateKeywordParam;
import com.bestcem.xm.txtanls.service.KeywordService;
import com.bestcem.xm.txtanls.service.dto.RecordSearchDTO;
import com.bestcem.xm.txtanls.service.dto.keyword.KeywordCountDTO;
import com.bestcem.xm.txtanls.service.dto.keyword.ListKeywordDTO;
import com.bestcem.xm.txtanls.service.dto.topic.TopicDTO;
import com.bestcem.xm.txtanls.service.dto.user.IndustryDTO;
import com.bestcem.xm.txtanls.util.FileUtils;
import com.bestcem.xm.txtanls.util.IndustryKeywordUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.bson.types.ObjectId;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

import static com.bestcem.xm.common.core.constant.Constants.*;

/**
 * @author liheng
 * @version v1.0
 * @date 2021/5/11-16:56
 */

@Service
@Slf4j
public class KeywordServiceImpl implements KeywordService {


    @Resource
    private IndustryKeywordUtil industryKeywordUtil;
    @Resource
    private TopicDao topicDao;
    @Resource
    private RecordDao recordDao;
    @Resource
    private HiddenKeywordDao hiddenKeywordDao;
    @Resource
    private AnalysisProjectDao analysisProjectDao;
    @Resource
    private IndustryToKeywordDao industryToKeywordDao;

    @Resource
    private BaseUserGrpcService baseUserGrpcService;

    @Resource
    private TrainModelDao trainModelDao;

    @Override
    public ServiceResult<ListKeywordDTO> listKeyword(ListKeywordParam listKeywordParam) {

        String projectId = listKeywordParam.getProjectId();
        String fieldId = listKeywordParam.getFieldId();
        if (StringUtils.isNotBlank(fieldId) && !ObjectId.isValid(fieldId)) {
            return ServiceResult.fail("fieldId错误");
        }
        int status = listKeywordParam.getStatus();
        ProjectDO projectDO = analysisProjectDao.findById(projectId);
        // 获取行业关键词或屏蔽关键词
        Set<String> keywords = this.listKeywords(projectId, projectDO.getModelId(), status);
        List<String> fieldIds = analysisProjectDao.listTextFiledId(projectId, fieldId);
        RecordSearchDTO recordSearchDTO = new RecordSearchDTO();
        recordSearchDTO.setProjectId(projectId);
        recordSearchDTO.setFieldIds(fieldIds);
        List<String> contents = recordDao.listRecordContent(recordSearchDTO);
        int recordSize = contents.size();
        List<TopicDO> topicDOEntities = topicDao.listTopicByKeywordExist(projectId);
        Map<String, Set<TopicDO>> wordMap = new HashMap<>(DEFAULT_MAP_SIZE);
        for (TopicDO topicDOEntity : topicDOEntities) {
            for (String s : topicDOEntity.getKeyDict()) {
                Set<TopicDO> valueList = wordMap.getOrDefault(s, new HashSet<>(DEFAULT_ARRAY_SIZE));
                valueList.add(topicDOEntity);
                wordMap.put(s, valueList);
            }
        }
        if (IndustryKeyWordStatusEnum.DISPLAY.getIndex() == status) {
            keywords.addAll(wordMap.keySet());
            HiddenKeywordDO hiddenKeywordsDO = hiddenKeywordDao.findHiddenKeywords(projectId);
            if (ObjectUtil.isNotNull(hiddenKeywordsDO) && CollUtil.isNotEmpty(hiddenKeywordsDO.getKeywordList())) {
                keywords.removeAll(hiddenKeywordsDO.getKeywordList());
            }
        }
        if (CollUtil.isEmpty(keywords)) {
            ListKeywordDTO listKeywordDTO = new ListKeywordDTO(Collections.emptyList(), (long) recordSize);
            return ServiceResult.success(listKeywordDTO);
        }
        List<KeywordCountDTO> keywordCountDTOS = new ArrayList<>();
        boolean hasTopic = CollUtil.isNotEmpty(topicDOEntities);
        BigDecimal totalSize = BigDecimal.valueOf(recordSize);
        for (String keyword : keywords) {
            ArrayList<TopicDTO> topicDTOs = new ArrayList<>(DEFAULT_ARRAY_SIZE);
            // 关键词关联话题信息
            if (hasTopic && wordMap.containsKey(keyword)) {
                Set<TopicDO> topicDOS = wordMap.get(keyword);
                for (TopicDO entry : topicDOS) {
                    TopicDTO topicDTO = TopicConvert.convertDTO(entry);
                    topicDTOs.add(topicDTO);
                }
            }
            // 关键词在原话中出现频率和次数
            int tempCount = 0;
            for (String content : contents) {
                if (content.contains(keyword)) {
                    tempCount++;
                }
            }
            // 原话记录数量为0
            double radio = 0;
            if (recordSize > 0) {
                radio = BigDecimal.valueOf(tempCount).divide(totalSize, 2, RoundingMode.DOWN).doubleValue();
            }
            keywordCountDTOS.add(new KeywordCountDTO(keyword, tempCount, radio, topicDTOs));
        }

        // 按照次数大小倒序排序
        keywordCountDTOS = keywordCountDTOS.stream().sorted(Comparator.comparing(KeywordCountDTO::getCount).reversed()).collect(Collectors.toList());
        return ServiceResult.success(new ListKeywordDTO(keywordCountDTOS, (long) recordSize));
    }

    /**
     * 查询项目关键词接口
     *
     * @param projectId
     * @param trainModelId
     * @param status
     * @return
     */
    private Set<String> listKeywords(String projectId, String trainModelId, int status) {
        Set<String> keywords = new HashSet<>(DEFAULT_ARRAY_SIZE);
        if (IndustryKeyWordStatusEnum.DISPLAY.getIndex() == status) {
            return this.listIndustryKeyword(trainModelId);
        } else if (IndustryKeyWordStatusEnum.SHIELD.getIndex() == status) {
            return this.listHiddenKeyword(projectId);
        }
        return keywords;
    }

    @Override
    public ServiceResult<Object> updateKeyword(UpdateKeywordParam updateKeywordParam) {
        String projectId = updateKeywordParam.getProjectId();
        if (KeywordOperationEnum.ADD.getIndex() == updateKeywordParam.getStatus()) {
            // 新增屏蔽关键词
            boolean updateResult = hiddenKeywordDao.addKeywords(projectId, updateKeywordParam.getKeyword());
            if (!updateResult) {
                return ServiceResult.fail("屏蔽的关键词保存成功");
            }
            return ServiceResult.success();
        } else if (KeywordOperationEnum.DELETE.getIndex() == updateKeywordParam.getStatus()) {
            // 删除屏蔽关键词
            boolean updateResult = hiddenKeywordDao.deleteKeywords(projectId, updateKeywordParam.getKeyword());
            if (!updateResult) {
                return ServiceResult.fail("删除屏蔽关键词失败");
            }
            return ServiceResult.success();
        } else {
            return ServiceResult.fail("status error");
        }
    }

    @Override
    public Collection<String> listKeywordByIndustryCode(String industryCode) {
        if (industryKeywordUtil.existKey(industryCode)) {
            // 读取行业关键词缓存
            JSONArray keywordByCode = industryKeywordUtil.getKeywordByCode(industryCode);
            List<String> strings = JSONArray.parseArray(keywordByCode.toJSONString(), String.class);
            if (CollUtil.isNotEmpty(strings)) {
                return new HashSet<>(strings);
            }
        }
        // 读行业关键词json文件
        Map<String, JSONArray> keywordMap = FileUtils.readIndustryKeywordFile(FileUtils.INDUSTRY_KEYWORD_FILE_PATH);
        if (Objects.isNull(keywordMap)) {
            return new HashSet<>(INT_ZERO);
        }
        JSONArray keyWords = keywordMap.get(industryCode);
        if (Objects.nonNull(keyWords) && CollUtil.isNotEmpty(keyWords)) {
            List<String> keywords = JSONArray.parseArray(keyWords.toJSONString(), String.class);
            Set<String> keywordsSet = new HashSet<>(keywords);
            industryKeywordUtil.cacheSingleIndustry(industryCode, JSONArray.parseArray(JSONArray.toJSONString(keywordsSet)));
            return keywordsSet;
        }
        return new HashSet<>(10);
    }

    @Override
    public Collection<IndustryKeywordDO> initIndustryKeyword(String orgId, IndustryDTO industry) {
        if (Objects.isNull(industry)) {
            // 查询出错,返回为空
            return Collections.emptyList();
        }
        String code = industry.getCode();
        if (StringUtils.isBlank(code)) {
            // 行业code为空，使用默认餐饮业
            code = String.valueOf(IndustryCodeEnum.DIET.getIndex());
        }
        Collection<String> keywords = this.listKeywordByIndustryCode(code);
        if (CollUtil.isEmpty(keywords)) {
            return new HashSet<>(INT_ZERO);
        }
        return industryToKeywordDao.insertOrgIndustryKeyword(orgId, industry.getId(), keywords);
    }

    /**
     * 查询行业关键词
     *
     * @param trainModelId 训练模型id
     * @return 行业关键词
     */
    @Override
    public Set<String> listIndustryKeyword(String trainModelId) {
        if (StringUtil.isNullOrEmpty(trainModelId)) {
            return new HashSet<>(10);
        }
        TrainModelDo trainModel = trainModelDao.getById(trainModelId);
        if (Objects.isNull(trainModel)) {
            return new HashSet<>(10);
        }
        Collection<String> strings = this.initIndustryKeywords(String.valueOf(trainModel.getCode()));
        return new HashSet<>(strings);
    }

    /**
     * 查询屏蔽关键词
     *
     * @param projectId 文本分析项目id
     * @return 屏蔽关键词
     */
    @Override
    public Set<String> listHiddenKeyword(String projectId) {
        HiddenKeywordDO hiddenKeywords = hiddenKeywordDao.findHiddenKeywords(projectId);
        if (ObjectUtils.isNotEmpty(hiddenKeywords)) {
            List<String> keywordList = hiddenKeywords.getKeywordList();
            if (CollUtil.isNotEmpty(keywordList)) {
                return new HashSet<>(keywordList);
            }
        }
        return new HashSet<>(10);
    }

    /**
     * 根据行业code查询行业关键词list
     *
     * @param trainModelCode 训练模型code
     * @return 行业关键词list
     */
    @Override
    public Collection<String> initIndustryKeywords(String trainModelCode) {
        if (industryKeywordUtil.existKey(trainModelCode)) {
            // 读取行业关键词缓存
            JSONArray keywordByCode = industryKeywordUtil.getKeywordByCode(trainModelCode);
            if (!keywordByCode.isEmpty()) {
                List<String> strings = JSONArray.parseArray(keywordByCode.toJSONString(), String.class);
                return new HashSet<>(strings);
            }
        }
        // 读行业关键词json文件
        Map<String, JSONArray> keywordMap = FileUtils.readIndustryKeywordFile(FileUtils.INDUSTRY_KEYWORD_FILE_PATH);
        if (Objects.isNull(keywordMap)) {
            return new HashSet<>(INT_ZERO);
        }
        JSONArray keyWords = keywordMap.get(trainModelCode);
        if (Objects.nonNull(keyWords) && CollUtil.isNotEmpty(keyWords)) {
            List<String> keywords = JSONArray.parseArray(keyWords.toJSONString(), String.class);
            Set<String> keywordsSet = new HashSet<>(keywords);
            industryKeywordUtil.cacheSingleIndustry(trainModelCode, JSONArray.parseArray(JSONArray.toJSONString(keywordsSet)));
            return keywordsSet;
        }
        return new HashSet<>(10);
    }

}
